package org.datascooter.bundle.attribute;

import org.datascooter.bundle.DSMapper;
import org.datascooter.bundle.EntityBundle;
import org.datascooter.exception.EntityNotMappedException;
import org.datascooter.impl.Condition;
import org.datascooter.impl.DataSnip;
import org.datascooter.impl.DataSnipFactory;

/**
 * This class purposed for mapping a persisted child objects. This objects, contained in parent in runtime and will be persisted with parent and tables may be linked with references
 * 
 * @author nemo
 * 
 */
public abstract class PersistChildAttribute extends ContainerAttribute {

	protected Boolean joinFromChild;
	protected String joinAttribute;
	protected boolean isParent;
	protected PersistAttribute reference;
	protected String parentEntity;
	protected boolean resolved = false;
	protected int arrayIndex = 0;

	public PersistChildAttribute(String name, String entity, String mapKeyAttribute, PersistencePolicy policy, boolean embedded, boolean fetchLazy, String joinAttribute, Boolean joinFromChild) {
		super(name);
		this.entity = entity;
		this.mapKeyAttribute = mapKeyAttribute;
		this.joinAttribute = joinAttribute;
		this.joinFromChild = joinFromChild;
		this.policy = (policy == null ? PersistencePolicy.ALL : policy);
		this.embedded = embedded;
		this.fetchLazy = fetchLazy;
	}

	@Override
	public void explore(Class<?> clazz) throws SecurityException, NoSuchMethodException {
		parentEntity = clazz.getName();
	}

	public void resolveReferrer() throws EntityNotMappedException, SecurityException, NoSuchMethodException {
		resolved = true;
		if (joinAttribute != null) {
			if (joinFromChild) {
				reference = DSMapper.getBundle(getEntity()).getAttribute(joinAttribute);
			} else {
				reference = DSMapper.getBundle(parentEntity).getAttribute(joinAttribute);
				if (reference != null) {
					arrayIndex = DSMapper.getBundle(parentEntity).getColumnIndex(reference.getColumnName());
					isParent = true;
				}
			}
		} else {
			reference = DSMapper.getBundle(getEntity()).getEntityReference(parentEntity);
			if (reference == null) {
				EntityBundle bundle = DSMapper.getBundle(parentEntity);
				reference = bundle.getEntityReference(getEntity());
				if (reference != null) {
					arrayIndex = bundle.getColumnIndex(reference.getColumnName());
					isParent = true;
				}
			}
		}
	}

	public DataSnip resolveQuery() throws EntityNotMappedException, SecurityException, NoSuchMethodException {
		if (query == null) {
			if (!resolved) {
				resolveReferrer();
			}
			if (reference != null) {
				query = DataSnipFactory.select(getEntity());
				if (joinAttribute != null) {
					if (joinFromChild) {
						query.join(joinAttribute, getEntity(), joinFromChild).where(reference.name, "");
					} else {
						query.whereId("");
					}
				} else {
					query.where(reference.name, "");
				}
			}
			if (condition != null) {
				query.where(condition);
			}
		}
		return query;
	}

	public Condition getCondition() {
		return condition;
	}

	public void setCondition(Condition condition) {
		this.condition = condition;
	}

	public void setQuery(DataSnip query) {
		this.query = query;
	}

	public String getJoinAttribute() {
		return joinAttribute;
	}

	public Boolean getJoinFromChild() {
		return joinFromChild;
	}

	public DataSnip getQuery() {
		return query;
	}

	public void setMapKeyAttribute(String attribute) {
		mapKeyAttribute = attribute;
	}

	public String getMapKeyAttribute() {
		return mapKeyAttribute;
	}

	public boolean isParent() {
		return isParent;
	}

	public PersistAttribute getReference() {
		return reference;
	}

	public boolean isResolved() {
		return resolved;
	}

	public int getArrayIndex() {
		return arrayIndex;
	}

	public final void setJoinAttribute(String joinAttribute) {
		this.joinAttribute = joinAttribute;
	}

	public String getEntity() {
		return entity;
	}
}
